package com.xjscrm.server.service.soptask.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.uzai.mobile.collect.api.dto.MicaTriggerDto;
import com.uzai.mobile.collect.api.dto.trigger.group.MicaTriggerGroupAddMsg;
import com.uzai.mobile.collect.api.dto.trigger.group.MicaTriggerGroupInviteMsg;
import com.uzai.mobile.collect.api.enums.MicaMsgSource;
import com.uzai.mobile.collect.api.enums.MicaTalkMsgType;
import com.uzai.mobile.collect.api.enums.MicaTriggerType;
import com.uzai.trace.TraceGenerate;
import com.xjscrm.common.annotation.MerId;
import com.xjscrm.common.entity.*;
import com.xjscrm.common.utils.DateUtil;
import com.xjscrm.common.utils.Tools;
import com.xjscrm.common.vo.grouppull.AgainData;
import com.xjscrm.common.vo.grouppull.GroupPullData;
import com.xjscrm.common.vo.grouppull.GroupPullMsgData;
import com.xjscrm.common.vo.msg.MsgData;
import com.xjscrm.common.vo.sop.SopDeviceRule;
import com.xjscrm.server.biz.RatelimitService;
import com.xjscrm.server.biz.mq.producer.SendMsgProducer;
import com.xjscrm.server.common.util.DeviceTools;
import com.xjscrm.server.common.util.Functions;
import com.xjscrm.server.common.util.SleepTimeTools;
import com.xjscrm.server.dto.sopjobmsg.SopJobMsgQuery;
import com.xjscrm.server.enums.LimitRedisCacheKeyEnum;
import com.xjscrm.server.mapper.*;
import com.xjscrm.server.service.msg.MsgSendService;
import com.xjscrm.server.service.soptask.SopJobMsgService;
import com.xjscrm.server.utils.DelayTopicHolder;
import com.xjscrm.server.vo.device.Device;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 群发任务异步实现类
 *
 * @author makejava
 * @since 2024-03-01 17:01:12
 */
@Slf4j
@Service
public class SopJobMsgServiceImpl implements SopJobMsgService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SopJobMsgMapper sopJobMsgMapper;
    @Autowired
    private SendMsgProducer sendMsgProducer;
    @Autowired
    private GroupPullMarketingMapper groupPullMarketingMapper;
    @Autowired
    private SopTemplateMapper sopTemplateMapper;
    @Autowired
    private WwDeviceMapper wwDeviceMapper;
    @Autowired
    private RatelimitService ratelimitService;
    @Autowired
    private WwCustomerBlacklistMapper wwCustomerBlacklistMapper;
    @Autowired
    private MsgSendService msgSendService;
    @Autowired
    private SopTaskDeviceConfigMapper sopTaskDeviceConfigMapper;

    /**
     * Sop消息拉群接口
     *
     * @param device 机器人信息
     * @return 实例对象
     */
    @Async("taskExecutorForXxJob")
    @TraceGenerate //注入消息id标签
    public void addSopJobMsg(SopJob sopJob, Integer sendTime, Device device, String wxid, String sendNickname, List<GroupPullMsgData> groupPullMsgDataList){

        if(sopJob == null){
            return;
        }

        if (device == null) {
            return;
        }

        if (StringUtils.isBlank(wxid)) {
            return;
        }

        if (groupPullMsgDataList == null || groupPullMsgDataList.size() == 0) {
            return;
        }

        int now = DateUtil.getTime();

        int delay = 0; //默认延迟时间为0;
        for (int i = 0; i < groupPullMsgDataList.size(); i++) {
            GroupPullMsgData groupPullMsgData = groupPullMsgDataList.get(i);
            delay = delay + Tools.getInteger(groupPullMsgData.getGap()) * Tools.getInteger(groupPullMsgData.getUnit());
            Integer msgType = Tools.getInteger(groupPullMsgData.getMsgType());
            if(msgType.intValue() != 101 && msgType.intValue() != 102){//普通消息

                SopJobMsg sopJobMsg = new SopJobMsg();
                sopJobMsg.setId(IdWorker.getId());
                sopJobMsg.setMerId(sopJob.getMerId());
                sopJobMsg.setTaskId(sopJob.getTaskId());
                sopJobMsg.setJobId(sopJob.getId());
                sopJobMsg.setStatus(1);
                sopJobMsg.setDeviceUniqueId(sopJob.getDeviceUniqueId());
                sopJobMsg.setDeviceId(sopJob.getDeviceId());
                sopJobMsg.setType(sopJob.getWxidType());
                sopJobMsg.setWxid(sopJob.getWxid());

                //替换[称呼/昵称]变量，优先称呼，在昵称
                if (groupPullMsgData.getMsgType().intValue() == MicaTalkMsgType.TEXT.getCode().intValue()) {//文本消息
                    String content = Tools.getStr(groupPullMsgData.getContent());
                    content = content.replace("[称呼/昵称]", Tools.getStr(sendNickname));
                    groupPullMsgData.setContent(content);
                }
                sopJobMsg.setMsgData(JSONObject.toJSONString(groupPullMsgData));
                sopJobMsg.setDelay(delay);
                sopJobMsg.setSendTime(sendTime);
                sopJobMsg.setUnsubscribe(0); //不是订阅消息
                sopJobMsg.setUnsubscribeKeyword(null);
                sopJobMsg.setCreateTime(now);
                sopJobMsg.setUpdateTime(now);
                sopJobMsgMapper.insertSelective(sopJobMsg);

            }else{
                if(msgType.intValue() == 101){ //拉进旧群
                    //发送拉群指令
                    MicaTriggerGroupInviteMsg micaTriggerGroupInviteMsg = new MicaTriggerGroupInviteMsg();
                    micaTriggerGroupInviteMsg.setGroupId(groupPullMsgData.getGroupId());
                    micaTriggerGroupInviteMsg.setWxIds(groupPullMsgData.getWxIds());
                    MicaTriggerDto micaTriggerDto = MicaTriggerDto.newInstance(micaTriggerGroupInviteMsg, MicaTriggerType.TRIGGER_GROUP_INVITE, Functions.fillTriggerMsg(device));
                    micaTriggerDto.setDelay(delay);
                    sendMsgProducer.pushMsgDelay(micaTriggerDto, DelayTopicHolder.getNextServer()); //发送延迟消息
                    try {
                        //未进群营销数据
                        List<AgainData> notJoinInvitationAgain = groupPullMsgData.getNotJoinInvitationAgain();
                        if (notJoinInvitationAgain != null && notJoinInvitationAgain.size() > 0) {//插入数据库
                            for (AgainData againData : notJoinInvitationAgain) {
                                //未进群，再次邀请间隔时间(单位：秒）
                                Integer againIntervalTime = Tools.getInteger(againData.getAgainIntervalTime());
                                //未进群，再次邀请拉群数据列表
                                List<GroupPullData> againGroupPullDatas = againData.getAgainGroupPullDatas();
                                if (againGroupPullDatas != null && againGroupPullDatas.size() > 0) {
                                    //拉近旧群才有未进群再次拉群营销数据，因为拉新群直接就进群了
                                    GroupPullMarketing groupPullMarketing = new GroupPullMarketing();
                                    groupPullMarketing.setId(IdWorker.getId());
                                    groupPullMarketing.setMerId(sopJob.getMerId());
                                    groupPullMarketing.setType(6); //类型（1；关键词拉群；2-标签拉群；3-批量拉群；4-新客户运营拉群；5-智能应答触发问题拉群；6-Sop任务拉群）
                                    groupPullMarketing.setPlanId(sopJob.getId());
                                    groupPullMarketing.setDeviceUniqueId(device.getDeviceUniqueId());
                                    groupPullMarketing.setDeviceId(device.getDeviceId());
                                    groupPullMarketing.setWxid(wxid);
                                    groupPullMarketing.setGroupWxid(groupPullMsgData.getGroupId());
                                    groupPullMarketing.setGroupPullDatas(JSONObject.toJSONString(againGroupPullDatas));
                                    groupPullMarketing.setStartTime(DateUtil.getTime());
                                    groupPullMarketing.setDelay(againIntervalTime + delay); //页面设置的延迟时间+延迟发送拉群时间
                                    groupPullMarketing.setStatus(1); //开启中，拉进旧群默认不开启
                                    groupPullMarketing.setModel(0); //不进群营销
                                    groupPullMarketing.setHander(0);
                                    groupPullMarketing.setHanderTime(null);
                                    groupPullMarketing.setCreateTime(DateUtil.getTime());
                                    groupPullMarketing.setUpdateTime(DateUtil.getTime());
                                    groupPullMarketingMapper.insertSelective(groupPullMarketing);
                                }
                            }
                        }

                        //开启已进群再次营销功能
                        List<AgainData> joinedMarketingAgain = groupPullMsgData.getJoinedMarketingAgain();
                        if (joinedMarketingAgain != null && joinedMarketingAgain.size() > 0) {//插入数据库
                            for (AgainData againData : joinedMarketingAgain) {
                                //已进群，再次营销间隔时间(单位：秒）
                                Integer againIntervalTime = Tools.getInteger(againData.getAgainIntervalTime());
                                //已进群，再次营销拉群数据列表
                                List<GroupPullData> againGroupPullDatas = againData.getAgainGroupPullDatas();
                                if (againGroupPullDatas != null && againGroupPullDatas.size() > 0) {
                                    GroupPullMarketing groupPullMarketing = new GroupPullMarketing();
                                    groupPullMarketing.setId(IdWorker.getId());
                                    groupPullMarketing.setMerId(sopJob.getMerId());
                                    groupPullMarketing.setType(6);//类型（1；关键词拉群；2-标签拉群；3-批量拉群；4-新客户运营拉群；5-智能应答触发问题拉群；6-Sop任务拉群）
                                    groupPullMarketing.setPlanId(sopJob.getId());
                                    groupPullMarketing.setDeviceUniqueId(device.getDeviceUniqueId());
                                    groupPullMarketing.setDeviceId(device.getDeviceId());
                                    groupPullMarketing.setWxid(wxid);
                                    groupPullMarketing.setGroupWxid(groupPullMsgData.getGroupId());
                                    groupPullMarketing.setGroupPullDatas(JSONObject.toJSONString(againGroupPullDatas));
                                    groupPullMarketing.setStartTime(DateUtil.getTime());
                                    groupPullMarketing.setDelay(againIntervalTime + delay); //页面设置的延迟时间+延迟发送拉群时间
                                    groupPullMarketing.setStatus(0);  //关闭中，进群通过才开启
                                    groupPullMarketing.setModel(1); //已进群营销
                                    groupPullMarketing.setHander(0);
                                    groupPullMarketing.setHanderTime(null);
                                    groupPullMarketing.setCreateTime(DateUtil.getTime());
                                    groupPullMarketing.setUpdateTime(DateUtil.getTime());
                                    groupPullMarketingMapper.insertSelective(groupPullMarketing);
                                }
                            }
                        }
                    }catch (Exception e){
                        log.error("插入入群营销数据失败", e.getMessage(), e);
                    }
                }else if(msgType.intValue() == 102){ //创建新群
                    //发送创建群指令
                    MicaTriggerGroupAddMsg micaTriggerGroupAddMsg = new MicaTriggerGroupAddMsg();
                    micaTriggerGroupAddMsg.setGroupName(groupPullMsgData.getGroupName());
                    micaTriggerGroupAddMsg.setWxIds(groupPullMsgData.getWxIds());
                    MicaTriggerDto micaTriggerDto = MicaTriggerDto.newInstance(micaTriggerGroupAddMsg, MicaTriggerType.TRIGGER_GROUP_ADD, Functions.fillTriggerMsg(device));
                    micaTriggerDto.setDelay(delay);
                    sendMsgProducer.pushMsgDelay(micaTriggerDto, DelayTopicHolder.getNextServer()); //发送延迟消息

                    try {
                        //开启已进群再次营销功能
                        List<AgainData> joinedMarketingAgain = groupPullMsgData.getJoinedMarketingAgain();
                        if (joinedMarketingAgain != null && joinedMarketingAgain.size() > 0) {//插入数据库
                            for (AgainData againData : joinedMarketingAgain) {
                                //已进群，再次营销间隔时间(单位：秒）
                                Integer againIntervalTime = Tools.getInteger(againData.getAgainIntervalTime());
                                //已进群，再次营销拉群数据列表
                                List<GroupPullData> againGroupPullDatas = againData.getAgainGroupPullDatas();
                                if (againGroupPullDatas != null && againGroupPullDatas.size() > 0) {
                                    GroupPullMarketing groupPullMarketing = new GroupPullMarketing();
                                    groupPullMarketing.setId(IdWorker.getId());
                                    groupPullMarketing.setMerId(sopJob.getMerId());
                                    groupPullMarketing.setType(6);//类型（1；关键词拉群；2-标签拉群；3-批量拉群；4-新客户运营拉群；5-智能应答触发问题拉群；6-Sop任务拉群）
                                    groupPullMarketing.setPlanId(sopJob.getId());
                                    groupPullMarketing.setDeviceUniqueId(device.getDeviceUniqueId());
                                    groupPullMarketing.setDeviceId(device.getDeviceId());
                                    groupPullMarketing.setWxid(wxid);
                                    groupPullMarketing.setGroupWxid(groupPullMsgData.getGroupId());
                                    groupPullMarketing.setGroupPullDatas(JSONObject.toJSONString(againGroupPullDatas));
                                    groupPullMarketing.setStartTime(DateUtil.getTime());
                                    groupPullMarketing.setDelay(againIntervalTime + delay); //页面设置的延迟时间+延迟发送拉群时间
                                    groupPullMarketing.setStatus(1); //开启中，创建新群表示直接拉进去了
                                    groupPullMarketing.setModel(1);  //已进群营销
                                    groupPullMarketing.setHander(0);
                                    groupPullMarketing.setHanderTime(null);
                                    groupPullMarketing.setCreateTime(DateUtil.getTime());
                                    groupPullMarketing.setUpdateTime(DateUtil.getTime());
                                    groupPullMarketingMapper.insertSelective(groupPullMarketing);
                                }
                            }
                        }
                    }catch (Exception e){
                        log.error("插入拉群营销数据失败，error={}",e.getMessage(), e);
                    }
                }
            }
        }

        //最后是否发送退订指令(私聊才有，群聊不发送退订消息)
        if(Tools.getInteger(sopJob.getWxidType()).intValue() == 0){
            SopTemplate sopTemplate = sopTemplateMapper.selectById(sopJob.getTeaplateId());
            if(sopTemplate != null){
                Integer unsubscribeSwitch = Tools.getInteger(sopTemplate.getUnsubscribeSwitch());
                if(unsubscribeSwitch.intValue() == 1){
                    String unsubscribeMsg = sopTemplate.getUnsubscribeMsg();
                    String unsubscribeKeyword = sopTemplate.getUnsubscribeKeyword();

                    SopJobMsg sopJobMsg = new SopJobMsg();
                    sopJobMsg.setId(IdWorker.getId());
                    sopJobMsg.setMerId(sopJob.getMerId());
                    sopJobMsg.setTaskId(sopJob.getTaskId());
                    sopJobMsg.setJobId(sopJob.getId());
                    sopJobMsg.setStatus(1);
                    sopJobMsg.setDeviceUniqueId(sopJob.getDeviceUniqueId());
                    sopJobMsg.setDeviceId(sopJob.getDeviceId());
                    sopJobMsg.setType(sopJob.getWxidType());
                    sopJobMsg.setWxid(sopJob.getWxid());

                    MsgData msgData = new MsgData();
                    msgData.setGap(delay+5);
                    msgData.setUnit(1);
                    msgData.setMsgType(MicaTalkMsgType.TEXT.getCode().intValue());
                    msgData.setContent(unsubscribeMsg);
                    sopJobMsg.setMsgData(JSONObject.toJSONString(msgData));

                    sopJobMsg.setDelay(delay+5); //延后5秒发送退订消息
                    sopJobMsg.setSendTime(sendTime);
                    sopJobMsg.setUnsubscribe(1); //是订阅消息
                    sopJobMsg.setUnsubscribeKeyword(unsubscribeKeyword);
                    sopJobMsg.setCreateTime(now);
                    sopJobMsg.setUpdateTime(now);
                    sopJobMsgMapper.insertSelective(sopJobMsg);
                }
            }
        }
    }

    /**
     * 将群发消息封装到MQ
     * @param merId
     * @return null
     * @author jitwxs
     * @date 2024/3/8 17:12
     */
    @Async("taskExecutorForXxJob")
    @TraceGenerate //注入消息id标签
    public void sendSopJobMsgToMqSync(@MerId Long merId){
        //限流key
        String taskLimitKey = "-TaskSendSopJobMsgToMqSync-LimitKey-merId=" + merId;
        Object object = redisTemplate.opsForValue().get(taskLimitKey);
        if (object != null) {
            return;
        }

        //保存限流key
        redisTemplate.opsForValue().set(taskLimitKey, merId, 100, TimeUnit.SECONDS);

        log.info("-----将群发消息封装到MQ----merId=" + merId);

        try {
            //查询当前所有开启的自动发圈的配置方案
            int now = DateUtil.getTime();
            SopJobMsgQuery sopJobMsgQuery = new SopJobMsgQuery();
            sopJobMsgQuery.setMerId(merId);
            sopJobMsgQuery.setStatus(1); //状态（1-未发送；2-已发送；3-发送失败(休眠时间))
            sopJobMsgQuery.setSendTimeEnd(now); //将将要发送的消息插入到mq当中
            sopJobMsgQuery.setDelayEnd(30);     //将延迟时间在30秒内的消息查询出来发送

            //查询所有的自动发圈配置记录
            Page<SopJobMsg> page = new Page<>();
            page.setCurrent(1);//只查第一页
            page.setSize(10); //每页查询10个
            page.addOrder(OrderItem.asc("id"));//默认id升序
            Long idStart = 0L;
            List<SopJobMsg> sopJobMsgList = sopJobMsgMapper.findByList(page, sopJobMsgQuery);
            while (sopJobMsgList != null && sopJobMsgList.size() > 0) {
                for (SopJobMsg sopJobMsg : sopJobMsgList) {

                    if (sopJobMsg.getId().longValue() >idStart.longValue()) {
                        idStart = sopJobMsg.getId();
                    }

                    //限流判断
                    String rateLimitKey = "sendSopJobMsgToMqSync-msgId=" + sopJobMsg.getId();
                    Object rateLimitKeyobject = redisTemplate.opsForValue().get(rateLimitKey);
                    if (rateLimitKeyobject == null) {
                        //保存限流key
                        redisTemplate.opsForValue().set(rateLimitKey, rateLimitKey, 300, TimeUnit.SECONDS);
                    } else {
                        continue;
                    }

                    try {

                        //封装机器人
                        WwDevice wwDevice = wwDeviceMapper.queryById(sopJobMsg.getDeviceUniqueId());
                        if(wwDevice == null) {
                            //处理群发任务
                            sopJobMsg.setStatus(3); //状态（1-未发送；2-已发送；3-发送失败)
                            sopJobMsg.setUpdateTime(DateUtil.getTime());
                            sopJobMsgMapper.updateStatusById(sopJobMsg);
                            continue;
                        }
                        Device device = DeviceTools.transDevice(wwDevice);

                        //本次发送时间=消息发送时间+延迟时间
                        Integer sendTime_this = Tools.getInteger(sopJobMsg.getSendTime()) + Tools.getInteger(sopJobMsg.getDelay());
                        //验证是否是机器人休眠时间
                        SopTaskDeviceConfig sopTaskDeviceConfig = sopTaskDeviceConfigMapper.selectByDeviceUniqueId(sopJobMsg.getDeviceUniqueId(), sopJobMsg.getMerId());
                        if(sopTaskDeviceConfig != null){
                            SopDeviceRule sopDeviceRule = JSONObject.parseObject(sopTaskDeviceConfig.getRule(), SopDeviceRule.class);
                            if(sopDeviceRule != null){
                                boolean sleepResult = SleepTimeTools.verifySopDeviceSleepTime(sopDeviceRule, new Date(sendTime_this.intValue() * 1000L));
                                if(sleepResult){
                                    //处理群发任务
                                    sopJobMsg.setStatus(3); //状态（1-未发送；2-已发送；3-发送失败)
                                    sopJobMsg.setUpdateTime(DateUtil.getTime());
                                    sopJobMsgMapper.updateStatusById(sopJobMsg);
                                    continue;
                                }
                            }
                        }

                        //处理群发任务
                        sopJobMsg.setStatus(2); //状态（1-未发送；2-已发送；3-发送失败)
                        sopJobMsg.setUpdateTime(DateUtil.getTime());
                        sopJobMsgMapper.updateStatusById(sopJobMsg);

                        MsgData msgData = JSONObject.parseObject(sopJobMsg.getMsgData(), MsgData.class);
                        //补偿延迟时间
                        int difDelay = DateUtil.getTime() - sendTime_this.intValue();
                        if(difDelay < 0){
                            difDelay = 0;
                        }
                        //消息发送时间
                        int msgSendDelay = sopJobMsg.getDelay() - difDelay;
                        if(msgSendDelay < 0){
                            msgSendDelay = sopJobMsg.getDelay();
                        }

                        if(msgData != null){
                            msgData.setGap(msgSendDelay);
                            msgData.setUnit(1);
                        }

                        //判断是否是群发
                        boolean group = false;
                        if(Tools.getInteger(sopJobMsg.getType()) == 1){
                            group = true;
                        }

                        msgSendService.msgSend(device, sopJobMsg.getWxid(), null, msgData, false, null, 0, MicaMsgSource.SOP.getCode(), group);

                        //如果是发送退订消息，还需要保存退订指令缓存
                        Integer unsubscribe = Tools.getInteger(sopJobMsg.getUnsubscribe());
                        if(unsubscribe.intValue() == 1){//是退订消息
                            String unsubscribeKey = String.format(LimitRedisCacheKeyEnum.SOP_JOB_UNSUBSCRIBE_KEYWORD.getKey(), sopJobMsg.getMerId(), sopJobMsg.getDeviceId(), sopJobMsg.getWxid(), sopJobMsg.getUnsubscribeKeyword());
                            long expiredTime = 60 + msgSendDelay;
                            redisTemplate.opsForValue().set(unsubscribeKey, sopJobMsg.getJobId(), expiredTime, TimeUnit.SECONDS);
                        }
                    } catch (Exception e) {
                        log.error("--封装群发消息失败--error={}", e.getMessage(), e);
                    }finally {
                        //保存成功之后，手动删除限流redisKey
                        redisTemplate.delete(rateLimitKey);
                    }
                }

                sopJobMsgQuery.setIdStart(idStart);
                sopJobMsgList = sopJobMsgMapper.findByList(page, sopJobMsgQuery);
            }
        } catch (Exception e) {
            log.info(e.getMessage(),e);
        } finally {
            //删除限流key
            redisTemplate.delete(taskLimitKey);
        }

    }


}
